@tool
class_name SkillAction
extends Node2D

#region 属性
@export var action_name:String:
	get():
		return name if not action_name else action_name
@export var action_desc:String
@export var auto_start_by_reset:bool = true
@export var modifier_prop:Array[Skill_Modifier_Prop]
# 释放条件
@export var release_condition:Condition
# 不满足释放条件的处理
@export var not_meet_release_condition_resolution:GameEnum.SkillNotMeetReleaseConditionResolution
# 释放消耗
@export var release_cost:Cost
# 不满足释放消耗的处理
@export var not_meet_release_cost_resolution:GameEnum.SkillNotMeetReleaseCostResolution
# 技能冷却时间
@export_range(0,INF) var skill_action_cooling_time:float
var skill_action_state:GameEnum.SkillActionState = GameEnum.SkillActionState.Init
var cur_action_idx:int
var cur_blackboard:Blackboard
var modifiers:Array[SkillModifier] = []
var skill:Skill
# 等待被添加的修改器队列（一般是等到Waiting时才进行实际的修改）
var wait_add_modifiers_queue:Array[SkillModifier] = []
var cooling_timer:CustomTimer
var is_completed:bool = false
var result:GameEnum.SkillReleaseResult = GameEnum.SkillReleaseResult.Success
var connect_obj_dict:Dictionary[Signal,ConnectObj] = {}
var release_args:Dictionary = {}
#endregion
#region 字段
## 当前是否正在释放
var is_releasing:bool:
	get:
		return skill_action_state == GameEnum.SkillActionState.Releasing
## 当前是否可用
var is_can_release:bool:
	get:
		return skill_action_state == GameEnum.SkillActionState.Waiting
## 当前已经冷却的时间
var cooled_time:float:
	get:
		if skill_action_state != GameEnum.SkillActionState.Cooling or not cooling_timer:
			return 0
		return cooling_timer.running_time_no_pause
## 当前冷却进度[0,1]
var cooled_progress:float:
	get:
		if skill_action_state != GameEnum.SkillActionState.Cooling or not cooling_timer:
			return 1
		return cooling_timer.progress
#endregion
#region 信号
# 初始化
signal skill_action_init(skill_action:SkillAction)
# 释放
signal skill_action_release(skill_action:SkillAction)
# 释放中
signal skill_action_releasing_process(skill_action:SkillAction)
signal skill_action_releasing_physics_process(skill_action:SkillAction)
# 释放完成
signal skill_action_release_completed(skill_action:SkillAction,release_result:GameEnum.SkillReleaseResult)
# 被打断
signal skill_action_interrupted(skill_action:SkillAction)
# 技能进入冷却时
signal skill_action_cool(skill_action:SkillAction)
# 技能冷却中（非物理更新）
signal skill_action_cooling_process(skill_action:SkillAction)
# 技能冷却中（物理更新）
signal skill_action_cooling_physics_process(skill_action:SkillAction)
# 技能冷却完成时
signal skill_action_cool_completed(skill_action:SkillAction)
# 销毁
signal skill_action_destroyed(skill_action:SkillAction)
# 输入
signal skill_action_unhandled_input(skill_action:SkillAction,event:InputEvent)
signal skill_action_unhandled_key_input(skill_action:SkillAction,event:InputEvent)
# 状态转换
signal skill_action_state_changed(skill_action:SkillAction,from_state:GameEnum.SkillActionState,to_state:GameEnum.SkillActionState)
#endregion

#region 基类方法
#endregion
#region 公共方法
## 初始化
func init(action_idx:int = -1,init_data:Dictionary = {},handle_func:Callable = Callable()):
	if skill_action_state != GameEnum.SkillActionState.Init:
		return
	cur_action_idx = action_idx
	if action_idx == -1:
		cur_blackboard = Blackboard.new(init_data)
	else:
		cur_blackboard = get_parent().cur_blackboard
	skill = cur_blackboard.get_value(SkillBlackboardKey.Skill)
	# 应用属性修改器
	for modifier in modifier_prop:
		modifier.Modify([self])
	if handle_func.is_valid():
		handle_func.call()
	is_completed = false
	result = GameEnum.SkillReleaseResult.Success
	set_update(false)
	change_state(GameEnum.SkillActionState.Waiting)
	skill_action_init.emit(self)
## 释放
func release(args:Dictionary = {},handle_func:Callable = Callable()):
	self.release_args = args
	if skill_action_state != GameEnum.SkillActionState.Waiting:
		return
	var res = check_can_release()
	if res == GameEnum.SkillReleaseStatus.DontMeetTheReleaseCondition:
		if not_meet_release_condition_resolution == GameEnum.SkillNotMeetReleaseConditionResolution.InterruptSkill:
			skill.agent.interrupt_skill(skill.skill_info.id)
	elif res == GameEnum.SkillReleaseStatus.DontMeetTheReleaseCost:
		if not_meet_release_cost_resolution == GameEnum.SkillNotMeetReleaseCostResolution.InterruptSkill:
			skill.agent.interrupt_skill(skill.skill_info.id)
	if res != GameEnum.SkillReleaseStatus.Success:
		return res
	do_release_cost()
	change_state(GameEnum.SkillActionState.Releasing)
	if handle_func.is_valid():
		handle_func.call()
	skill_action_release.emit(self)
	## 释放完立即检查是否能结束
	if check_is_completed():
		complete(result)
## 打断
func interrupt(handle_func:Callable = Callable()):
	if skill_action_state != GameEnum.SkillActionState.Releasing:
		return
	change_state(GameEnum.SkillActionState.Interrupted)
	if handle_func.is_valid():
		handle_func.call()
	skill_action_interrupted.emit(self)
	cool()
## 完成
func complete(release_result:GameEnum.SkillReleaseResult = GameEnum.SkillReleaseResult.Success,handle_func:Callable = Callable()):
	if skill_action_state != GameEnum.SkillActionState.Releasing:
		return
	if handle_func.is_valid():
		handle_func.call()
	change_state(GameEnum.SkillActionState.Completed)
	skill_action_release_completed.emit(self,release_result)
	cool()
## 冷却
func cool(handle_func:Callable = Callable()):
	if skill_action_state != GameEnum.SkillActionState.Interrupted and skill_action_state != GameEnum.SkillActionState.Completed:
		return
	if cooling_timer:
		GameCustomTimerSystem.remove_timer(cooling_timer.id)
		cooling_timer = null
	if handle_func.is_valid():
		handle_func.call()
	change_state(GameEnum.SkillActionState.Cooling)
	skill_action_cool.emit(self)
## 冷却完成
func cool_complete(handle_func:Callable = Callable()):
	if cooling_timer:
		GameCustomTimerSystem.remove_timer(cooling_timer.id)
		cooling_timer = null
	if handle_func.is_valid():
		handle_func.call()
	is_completed = false
	result = GameEnum.SkillReleaseResult.Success
	change_state(GameEnum.SkillActionState.Waiting)
	skill_action_cool_completed.emit(self)
## 重置冷却
func reset_cool(handle_func:Callable = Callable()):
	if skill_action_state != GameEnum.SkillActionState.Cooling:
		return
	cool_complete()
## 销毁
func destroy(handle_func:Callable = Callable()):
	interrupt()
	for connect_obj in connect_obj_dict.values():
		if connect_obj:
			connect_obj.disconnect_all()
	connect_obj_dict.clear()
	if cooling_timer:
		GameCustomTimerSystem.remove_timer(cooling_timer.id)
		cooling_timer = null
	if handle_func.is_valid():
		handle_func.call()
	change_state(GameEnum.SkillActionState.Destroyed)
	skill_action_destroyed.emit(self)
	queue_free()
## 判断该技能能否释放
func check_can_release() -> GameEnum.SkillReleaseStatus:
	if skill_action_state == GameEnum.SkillActionState.Init:
		return GameEnum.SkillReleaseStatus.NoInited
	elif skill_action_state == GameEnum.SkillActionState.Releasing:
		return GameEnum.SkillReleaseStatus.Releasing
	elif skill_action_state == GameEnum.SkillActionState.Cooling:
		return GameEnum.SkillReleaseStatus.Cooling
	# 检查开始条件
	if not check_release_condition():
		match not_meet_release_condition_resolution:
			GameEnum.SkillNotMeetReleaseConditionResolution.Ignore:
				return GameEnum.SkillReleaseStatus.DontMeetTheReleaseCondition
			GameEnum.SkillNotMeetReleaseConditionResolution.InterruptSkill:
				return GameEnum.SkillReleaseStatus.DontMeetTheReleaseCondition
			_:
				pass
	# 检查开始消耗
	if not check_release_cost():
		match not_meet_release_cost_resolution:
			GameEnum.SkillNotMeetReleaseCostResolution.Ignore:
				return GameEnum.SkillReleaseStatus.DontMeetTheReleaseCost
			GameEnum.SkillNotMeetReleaseCostResolution.InterruptSkill:
				return GameEnum.SkillReleaseStatus.DontMeetTheReleaseCost
			_:
				pass
	return GameEnum.SkillReleaseStatus.Success
## 判断技能是否释放完成（默认返回true，代表可以直接结束，也可以添加一些处理逻辑，实现强制结束（例如持续施法消耗不够））
func check_is_completed() -> bool:
	return true
func add_modifier(modifier:SkillModifier):
	wait_add_modifiers_queue.append(modifier)
func handle_wait_add_modifiers_queue():
	if skill_action_state != GameEnum.SkillActionState.Waiting:
		return
	for modifier in wait_add_modifiers_queue:
		modifiers.append(modifier)
		modifier.Modify([self])
	wait_add_modifiers_queue.clear()
func get_agent() -> SkillAgent:
	return cur_blackboard.get_value(SkillBlackboardKey.Agent)
func get_entity() -> Entity:
	return skill.agent.entity
func check_release_condition():
	if release_condition != null and not release_condition.check_result(get_entity()):
		return false
	return true
func check_release_cost():
	if release_cost != null:
		var entity = get_entity()
		if entity:
			return release_cost.check_cost(entity)
		return false
	return true
func do_release_cost():
	if release_cost:
		var entity = get_entity()
		if entity:
			return release_cost.do_cost(entity)
		return false
	return true
func set_update(enable:bool):
	set_process(enable)
	set_physics_process(enable)
## 状态转换
func change_state(to_state:GameEnum.SkillActionState):
	# 检查状态转换是否合法
	if not is_valid_state_transition(skill_action_state, to_state):
		return false
	var from_state = skill_action_state
	before_state_change(from_state,to_state)
	skill_action_state = to_state
	after_state_change(from_state,to_state)
	skill_action_state_changed.emit(self,from_state,to_state)
## 检查状态转换是否合法
func is_valid_state_transition(from_state:GameEnum.SkillActionState, to_state:GameEnum.SkillActionState) -> bool:
	# 不允许转换到相同状态
	if from_state == to_state:
		return false
	
	# Init可以转换到Waiting
	if from_state == GameEnum.SkillActionState.Init:
		return to_state == GameEnum.SkillActionState.Waiting
	
	# 不允许从Destroyed状态转换
	if from_state == GameEnum.SkillActionState.Destroyed:
		return false
		
	# 不允许转换到Init状态
	if to_state == GameEnum.SkillActionState.Init:
		return false
		
	# 从Waiting状态可以转换到任何非Init状态
	if from_state == GameEnum.SkillActionState.Waiting:
		return true
		
	# 从Releasing状态只能转换到Completed或Interrupted状态
	if from_state == GameEnum.SkillActionState.Releasing:
		return to_state == GameEnum.SkillActionState.Completed or to_state == GameEnum.SkillActionState.Interrupted
		
	# 从Completed或Interrupted状态只能转换到Cooling状态
	if from_state == GameEnum.SkillActionState.Completed or from_state == GameEnum.SkillActionState.Interrupted:
		return to_state == GameEnum.SkillActionState.Cooling
		
	# 从Cooling状态只能转换到Waiting状态
	if from_state == GameEnum.SkillActionState.Cooling:
		return to_state == GameEnum.SkillActionState.Waiting
		
	return false
## 状态转换前的处理
func before_state_change(from_state:GameEnum.SkillActionState, to_state:GameEnum.SkillActionState):
	match from_state:
		GameEnum.SkillActionState.Releasing:
			# 停止更新
			set_update(false)
		GameEnum.SkillActionState.Cooling:
			# 停止更新
			set_update(false)
			# 清理冷却计时器
			if cooling_timer:
				GameCustomTimerSystem.remove_timer(cooling_timer.id)
				cooling_timer = null
## 状态转换后的处理
func after_state_change(from_state:GameEnum.SkillActionState, to_state:GameEnum.SkillActionState):
	match to_state:
		GameEnum.SkillActionState.Releasing:
			# 开始更新
			set_update(true)
		GameEnum.SkillActionState.Cooling:
			# 开始更新
			set_update(true)
			# 创建冷却计时器
			if skill_action_cooling_time > 0:
				cooling_timer = GameCustomTimerSystem.create_timer(skill_action_cooling_time)
				cooling_timer.register_listener(cooling_timer.timer_finished, func():
					cool_complete()
				)
			else:
				cool_complete()
		GameEnum.SkillActionState.Waiting:
			# 处理等待添加的修改器
			handle_wait_add_modifiers_queue()
#region SkillEditor
func get_clone() -> SkillAction:
	var clone:SkillAction = duplicate()
	clone.modifier_prop = modifier_prop.duplicate(true)
	clone.release_condition = release_condition.duplicate(true)
	clone.release_cost = release_cost.duplicate(true)
	return clone
func get_export_property_name_list() -> Array[String]:
	var list:Array[String] = []
	list.append_array([
		"action_name","action_desc","auto_start_by_reset",
		])
	return list
func get_connection_info() -> Dictionary:
	var args = {}
	args.set("parent_max_connections",999)
	var parent_port_allow_types = [] as Array[GameEnum.SkillNodeType]
	parent_port_allow_types.append_array(GameEnum.SkillNodeType.values())
	args.set("parent_port_allow_types",parent_port_allow_types)
	args.set("children_max_connections",999)
	var children_port_allow_types = [] as Array[GameEnum.SkillNodeType]
	children_port_allow_types.append_array(GameEnum.SkillNodeType.values())
	args.set("children_port_allow_types",children_port_allow_types)
	return args
#endregion
#endregion
#region 私有方法
#endregion
#region 生命周期函数
func _process(delta: float) -> void:
	if skill_action_state == GameEnum.SkillState.Releasing:
		skill_action_releasing_process.emit(self)
		if check_is_completed():
			complete(result)
	elif skill_action_state == GameEnum.SkillState.Cooling:
		skill_action_cooling_process.emit(self)
func _physics_process(delta: float) -> void:
	if skill_action_state == GameEnum.SkillState.Releasing:
		skill_action_releasing_physics_process.emit(self)
		if check_is_completed():
			complete(result)
	elif skill_action_state == GameEnum.SkillState.Cooling:
		skill_action_cooling_physics_process.emit(self)
func _unhandled_input(event: InputEvent) -> void:
	skill_action_unhandled_input.emit(self,event)
func _unhandled_key_input(event: InputEvent) -> void:
	skill_action_unhandled_key_input.emit(self,event)
func _exit_tree() -> void:
	pass
func _notification(what: int) -> void:
	pass
func _get_configuration_warnings() -> PackedStringArray:
	var warnings = []
	if get_children().filter(func(x):return x is SkillAction).size() > 0:
		warnings.append("此节点下面的SkillAction节点无法执行！")
	return warnings
#endregion
